#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

// 检测类型 T 是否可以与类型 U 相加
template <typename T, typename U, typename = void>
struct is_addable : std::false_type { };

template <typename T, typename U>
struct is_addable<T, U, std::void_t<decltype(std::declval<T>() + std::declval<U>())>>
    : std::true_type { };

static_assert(is_addable<int, double>::value, "int + double 可加");
static_assert(!is_addable<int, std::string>::value, "int + string 不可加");

template <typename T>
struct is_pointer : std::false_type { };
template <typename T>
struct is_pointer<T*> : std::true_type { };

template <typename T>
void check(T)
{
    if constexpr (is_pointer<T>::value) {
        std::cout << "T is a pointer type\n";
    } else {
        std::cout << "T is not a pointer type\n";
    }
}

template <typename T, typename Enable = void>
struct has_value_type : std::false_type { };
template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type { };

template <typename T, typename = void>
struct has_begin : std::false_type { };
template <typename T>
struct has_begin<T, typename std::enable_if<std::is_same<decltype(std::declval<T>().begin()), typename T::iterator>::value>::type>
    : std::true_type { };

template <typename T, typename = void>
struct has_begin_t : std::false_type { };
template <typename T>
struct has_begin_t<T, std::void_t<decltype(std::declval<T>().begin())>>
    : std::true_type { };

int main()
{
    int x = 42;
    int* p = &x;
    check(x); // T is not a pointer type
    check(p); // T is a pointer type

    if (has_begin<int>::value) {
        std::cout << "int has begin" << std::endl;
    } else {
        std::cout << "int dont has begin" << std::endl;
    }

    if (has_begin_t<std::vector<int>>::value) {
        std::cout << "std::vector<int>> has begin" << std::endl;
    } else {
        std::cout << "std::vector<int>> dont has begin" << std::endl;
    }

    return 0;
}